package cn.wen.rpc.proxy;

import cn.wen.rpc.annotation.WenReference;
import cn.wen.rpc.exception.WenRpcException;
import cn.wen.rpc.message.WenRequest;
import cn.wen.rpc.message.WenResponse;
import cn.wen.rpc.netty.client.NettyClient;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

@Slf4j
public class WenRpcClientProxy implements InvocationHandler {

    private WenReference wenReference;
    private NettyClient nettyClient;

    public WenRpcClientProxy(WenReference msReference, NettyClient nettyClient) {
        this.wenReference = msReference;
        this.nettyClient = nettyClient;
    }

    // 当接口 实现调用的时候，实际上是代理类的invoke方法被调用了
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 实现业务，向服务提供方发起网络请求，获取结果 并返回
        log.info("rpc 服务消费方 发起了调用..... invoke调用了");
        // 1. 构建请求数据WenRequest
        // 2. 创建Netty客户端
        // 3. 通过客户端向服务端发送请求
        // 4. 接收数据
        String version = wenReference.version();
        WenRequest wenRequest = WenRequest.builder()
                .group("wen-rpc")
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .version(version)
                .parameters(args)
                .paramTypes(method.getParameterTypes())
                .requestId(UUID.randomUUID().toString())
                .build();
        Object sendRequest = nettyClient.sendRequest(wenRequest);
        CompletableFuture<WenResponse<Object>> resultCompletableFuture = (CompletableFuture<WenResponse<Object>>) sendRequest;

        WenResponse<Object> wenResponse = resultCompletableFuture.get();
        if (wenResponse == null){
            throw new WenRpcException("服务调用失败");
        }
        if (!wenRequest.getRequestId().equals(wenResponse.getRequestId())){
            throw new WenRpcException("响应结果和请求不一致");
        }
        return wenResponse.getData();
    }

    /**
     * 通过接口 生成代理类
     * @param interfaceClass
     * @param <T>
     * @return
     */
    public <T> T getProxy(Class<T> interfaceClass) {
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class<?>[]{interfaceClass},this);
    }
}
